﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.IO;
using System.Data;
using System.Data.SqlClient;
using Common;
using System.Windows.Forms;


namespace ClsHttpServerPool
{
    public class ClsHttpServerPool
    {
    

        HttpListener Listerner = new HttpListener();
       
        public ClsHttpServerPool(int port)
        {
            Listerner.AuthenticationSchemes = AuthenticationSchemes.Anonymous;//指定身份验证 Anonymous匿名访问
            IPAddress[] ips = System.Net.Dns.GetHostAddresses(System.Net.Dns.GetHostName());  //绑定本机所有IP地址
            for (int i = 0; i < ips.Length; i++)                                              //设定域名
            {
                if (ips[i].AddressFamily == AddressFamily.InterNetwork) //IPv4地址 
                {

                    Listerner.Prefixes.Add("http://" + ips[i].ToString() + ":" + port.ToString() + "/");
                }
            }

            ThreadPool.SetMaxThreads(50, 1000);
            ThreadPool.SetMinThreads(50, 50);
        }



        /// <summary>
        /// 启动WEB服务,使用线程池
        /// </summary>
        public void Start()
        {
            Listerner.Start();
             
            while (true)
            { 
              HttpListenerContext Request=  Listerner.GetContext();   //如果没有连接，就阻塞当前的线程。有
              ThreadPool.QueueUserWorkItem(ProcessRequest, Request);   //用线程池
          
            }
       

        }


       

        public void Stop()
        {
            Listerner.Stop();
           
        }

        private void ProcessRequest(object listenerContext)

        {
                var context = (HttpListenerContext)listenerContext;
                new ClsProcessRequest().Begin(context);
        
        }

    }










   class  ClsProcessRequest
   {
       private string BaseFolder = Application.StartupPath+"\\PhotoDir\\";   //总的文件夹

       private string OneSubFolder = ""; //第一层
       
       private string SecondSubFolder = ""; //第二层

       volatile HttpListenerContext context; //volatile 从内存中读取，而不从cpu高速缓存中读取，避免此变量被其他线程意外修改后读取，这样就不是最新的了。

   
       volatile int bytesRead = 0;

       string filename = "";
       int DataLen =0;
     


       byte[]   MyBytes = new byte[1024 * 8];

       HttpProtocolHandler MyHttpProtocolHandler = new HttpProtocolHandler();
       HttpClsMessage MyHttpClsMessage=new HttpClsMessage();

       public ClsProcessRequest()
       {
            

           //新建文件夹
           OneSubFolder = BaseFolder + DateTime.Now.Year.ToString() + "-" + DateTime.Now.Month.ToString() + "\\";  //子目录,以当前的日期为准。一个月一个子文件夹
           SecondSubFolder = OneSubFolder + DateTime.Now.Year.ToString() + "-" + DateTime.Now.Month.ToString() + "-" + DateTime.Now.Day.ToString() + "\\";  //子目录,以当前的日期为准。一个月一个子文件夹

         if(Directory.Exists(BaseFolder)==false)
         {
           Directory.CreateDirectory(BaseFolder);
         }


         if (Directory.Exists(OneSubFolder) == false)
         {
             Directory.CreateDirectory(OneSubFolder);
         }

         if (Directory.Exists(SecondSubFolder) == false)
         {
             Directory.CreateDirectory(SecondSubFolder);
         }
       



       }


      internal void Begin(HttpListenerContext context)
      {
          try {

              this.context = context;
              this.context.Response.StatusCode = 200;//设置返回给客服端http状态代码
              DataLen =  Convert.ToInt32(context.Request.ContentLength64);

              filename = Path.GetFileName(context.Request.RawUrl);
              System.Diagnostics.Debug.WriteLine("---------------------------------------------------------------");
              System.Diagnostics.Debug.WriteLine("原始url:" + context.Request.RawUrl);
              System.Diagnostics.Debug.WriteLine("字符总大小:" + DataLen.ToString());
              System.Diagnostics.Debug.WriteLine("客户端的IP:" + context.Request.RemoteEndPoint.ToString());
              System.Diagnostics.Debug.WriteLine("上传的文件名:" + filename);

                 
                      //分析传过来的协议

             string[]  Protocols=  MyHttpProtocolHandler.GetProtocol(filename);
             foreach (string str in Protocols)
             {
                MyHttpClsMessage= HttpProtocolHandler.DePackMessage(str);
             }



             switch (MyHttpClsMessage.ComType)
            {
                 case "":
                Write("文件没找到,你懂的。");
                    break;


                 case HttpCommandType.DownloadFile:
                    DownloadFile(MyHttpClsMessage.DownFileName);
                    break;

                 case HttpCommandType.UploadFile:
                    Read();  //如果上传文件，那么就读取上传上来的数据。存为文件。
                    break;


                 default:
                    Write("不知道你的是啥请求。");
                    break;
            
            }

                
              
          
          }

          catch (Exception ex)
          {

              System.Diagnostics.Debug.WriteLine("--------------Begin请求的时候出错了----------------------");
              System.Diagnostics.Debug.WriteLine(ex.Message);
              ProcessException(ex);
               
          }
           

        
      }



      #region 发送的文件
      private void DownloadFile(string FileName)    //查看的时候要遍历文件夹,看是否有这个文件
      {
          try
          {
              //遍历文件夹下的文件
              string FullFileName = GetFilePath(new DirectoryInfo(BaseFolder), FileName);



              System.Diagnostics.Debug.WriteLine("---------------------------------------------");
              System.Diagnostics.Debug.WriteLine("------请求文件的完整路径--------------" + FullFileName);

              //------------------------------------------------

             if (FullFileName!="")   //如果存在
              {

                  using (System.IO.FileStream fs = new FileStream(FullFileName, FileMode.Open, FileAccess.Read))
                  {
                      byte[] picbyte = new byte[fs.Length];
                      using (BinaryReader br = new BinaryReader(fs))
                      {
                          picbyte = br.ReadBytes(Convert.ToInt32(fs.Length));
                          Write(picbyte);
                      }
                  }
                  System.Diagnostics.Debug.WriteLine("------文件存在--------------" + FullFileName);
              
              }




  

              else //不存在此文件。
              {
                  System.Diagnostics.Debug.WriteLine("------文件不存在--------------" + FullFileName);
                  Write("你请求的文件不存在。file not found");

              }
          }

          catch (Exception ex)
          {
              ProcessException(ex);
          }


      }

      #endregion




      #region 读取上传过来的数据
       void Read()
      {
          
          try
          {
              context.Request.InputStream.BeginRead(MyBytes, 0, MyBytes.Length, ReadCallback, null); //一次性把全部数据读入缓冲区？ 
          }
          catch (Exception ex)
          {
              ProcessException(ex);
          }
      }


      void ReadCallback(IAsyncResult r)
      {
          try
          {
                

              int ReadSize = context.Request.InputStream.EndRead(r); //把文件写进去

              System.Diagnostics.Debug.WriteLine("收到的字符大小:" + ReadSize.ToString());
              if (ReadSize > 0)   //如果数据没有接受完，那么就return, 不执行write。有数据就继续读。递归直到写完。
              {

                  using (Stream stream = new FileStream(SecondSubFolder + MyHttpClsMessage.UploadFileName, FileMode.Append, FileAccess.Write))
                  {
                      //将字符信息写入文件系统
                      stream.Write(MyBytes, 0, ReadSize);  //写的时候自动调整了位置。
                  }

                  bytesRead += ReadSize;
                   Read();
                   return;
              }

               //最后ReadSize=0;,然后执行write,关闭连接。最内层的Read发出的write。
              Write("0");  

             
              System.Diagnostics.Debug.WriteLine("发送消息给浏览器。" );

          }

          catch (Exception ex)
          {
              ProcessException(ex);
          
          }
      
      }
      #endregion


      #region 发送给浏览器


      void Write(string Data)
      {
          try
          {

              byte[] byteData = Encoding.GetEncoding("gb2312").GetBytes(Data);         //返回给浏览器的信息
              //  byte[] byteData = ASCIIEncoding.ASCII.GetBytes(Data);         //返回给浏览器的信息
              context.Response.OutputStream.BeginWrite(byteData, 0, byteData.Length, WriteCallback, null);
          }

          catch (Exception ex)
          {
              ProcessException(ex);

          }


      }

      void Write(byte[] byteData)
      {
          try
          {

              // byte[] byteData = Encoding.GetEncoding("gb2312").GetBytes(Data);         //返回给浏览器的信息
              //  byte[] byteData = ASCIIEncoding.ASCII.GetBytes(Data);         //返回给浏览器的信息
              context.Response.OutputStream.BeginWrite(byteData, 0, byteData.Length, WriteCallback, null);
          }

          catch (Exception ex)
          {
              ProcessException(ex);

          }


      }







      void WriteCallback(IAsyncResult r)
      {
          try
          {

              context.Response.OutputStream.EndWrite(r);
          }
          catch (Exception ex)
          {
              ProcessException(ex);
          }
          Cleanup();

      }

      #endregion




      void ProcessException(Exception ex)
      {
          Cleanup();
       
        
    

      }




      void Cleanup()
      {
          try
          {
              //----连接没有关闭。
              //发送给浏览器只跟输出流有关，如果不关闭输出流，那么浏览器就一直得不到响应。
              if (context.Request.InputStream != null)
              {
                  context.Request.InputStream.Close();
                  System.Diagnostics.Debug.WriteLine("输入流关闭了。");
              }

              if (context.Response.OutputStream != null)
              {
                  context.Response.OutputStream.Close();
                  System.Diagnostics.Debug.WriteLine("输出流关闭了。");
              }
          }

          catch (Exception ex)
          {
              System.Diagnostics.Debug.WriteLine("----------------Cleanup的时候报错了。----------------------------"); //
              System.Diagnostics.Debug.WriteLine(ex.Message); //
          }
      

      }



       /// <summary>
       /// 是否有这个文件，如果有就返回路径，没有返回""
       /// </summary>
       /// <param name="Floder"></param>
       /// <param name="FileName"></param>
       /// <returns></returns>
      private string GetFilePath(DirectoryInfo Floder,string FileName)
      {
          string FullPath = "";


      

          foreach (FileInfo NextFile in Floder.GetFiles())  //遍历文件
          {

              if (NextFile.Name == FileName)
              {
                  FullPath = NextFile.FullName;
                  return FullPath;
              }

            
          }

          //找不到就遍历子文件夹
          foreach (DirectoryInfo SubFolder in Floder.GetDirectories())  //遍历文件夹
          {
              FullPath = GetFilePath(SubFolder, FileName);
              if (FullPath != "")  //如果找到了,直接就返回，不再遍历同级的其他文件夹了。
              {
                  return FullPath;
              }
          }



 

          return FullPath;
      
      }







    


   }

}
